package tobsn.locationcalendar.map;

import tobsn.locationcalendar.NotificationListActivity;
import tobsn.locationcalendar.R;
import tobsn.locationcalendar.db.DBAdapter;
import tobsn.locationcalendar.db.DBOpenHelper;
import tobsn.locationcalendar.map.overlays.CurrenLocationOverlay;
import tobsn.locationcalendar.map.overlays.EditPONOverlay;
import tobsn.locationcalendar.map.overlays.ExistingPONOverlay;
import tobsn.locationcalendar.service.NotificationService;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

public class TobsnMapActivity extends MapActivity {

	public static final String PROX_ALERT_INTENT = "com.tobsn.ProximityAlert";
	public static final String EXTRA_NOTIFICATION_ID = "NOTIFICATION_ID";
	private static final float POINT_RADIUS = 1000f; // in Meters
	private static final long PROX_ALERT_EXPIRATION = 10000000;

	private DBAdapter mDBAdapter;
	private LocationManager mLocManager;
	private CurrentLocationListener mListener;
	private long mCurrentID;

	private MapView mMapView;
	private CurrenLocationOverlay mCurrentLocationOverlay;
	private EditPONOverlay mEditOverlay;
	private ExistingPONOverlay mExistingNotifications;

	private boolean isSatelite = false;
	private boolean hasUpdatedPosition = false;
	private boolean isEditing = false;
	private boolean isNewPON = false;

	private EditText mPONText;
	private View mPopup;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// set up view
		setContentView(R.layout.tobsnmap);
		mMapView = (MapView) findViewById(R.id.tobsnmapview);
		mMapView.setBuiltInZoomControls(true);
		final Button saveButton = (Button) findViewById(R.id.saveBtn);
		saveButton.setOnClickListener(mSaveListener);
		final Button deleteButton = (Button) findViewById(R.id.deleteBtn);
		deleteButton.setOnClickListener(mDeleteListener);
		final Button testProviderButton = (Button) findViewById(R.id.testProviderBtn);
		testProviderButton.setOnClickListener(mTestProviderListener);
		mPONText = (EditText) findViewById(R.id.NotificationText);
		setViewItemsVisibility(View.INVISIBLE, false);
		mPopup = getLayoutInflater()
				.inflate(R.layout.mappopup, mMapView, false);

		mDBAdapter = new DBAdapter(this);

		// Acquire a reference to the system Location Manager
		mLocManager = (LocationManager) this
				.getSystemService(Context.LOCATION_SERVICE);
		mListener = new CurrentLocationListener(this);
		mLocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0,
				0, mListener);
		mLocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
				mListener);

		Location location = mLocManager
				.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
		Double lat;
		Double lng;
		if (location == null) {
			Log.w("LastKnownLocation",
					"The last known location could not be resolved");
			lat = 47.2345;
			lng = 32.5678;
		} else {
			lat = location.getLatitude() * 1E6;
			lng = location.getLongitude() * 1E6;
		}
		GeoPoint p = new GeoPoint(lat.intValue(), lng.intValue());
		mMapView.getController().setCenter(p);

		// set up overlays
		Drawable drawable = this.getResources().getDrawable(R.drawable.dot1315);
		mCurrentLocationOverlay = new CurrenLocationOverlay(drawable);
		mCurrentLocationOverlay.updatePosition(p);

		Drawable notificationDrawable = this.getResources().getDrawable(
				R.drawable.droid);
		mExistingNotifications = new ExistingPONOverlay(notificationDrawable,
				this);
		mExistingNotifications.updateOverlay();

		mMapView.getOverlays().add(mExistingNotifications);
		mMapView.getOverlays().add(mCurrentLocationOverlay);

	}

	public void showDistance() {
		Cursor c;
		mDBAdapter.open();
		c = mDBAdapter.fetchAllPON();
		GeoPoint p = mListener.getCurrentLocation();
		int lat = p.getLatitudeE6();
		int lng = p.getLongitudeE6();
		while (c.moveToNext()) {
			float results[] = new float[1];
			Location.distanceBetween(c.getInt(DBOpenHelper.LATITUDE_INT),
					c.getInt(DBOpenHelper.LONGITUDE_INT), lat, lng, results);
			Log.d("Distance between current and "
					+ c.getString(DBOpenHelper.TEXT_INT),
					String.valueOf(results[0]));
		}
		c.close();
		mDBAdapter.close();
	}

	/**
	 * Sets the overlay to the current position
	 * 
	 * @param currentPosition
	 */
	public void updatePosition(GeoPoint currentPosition) {
		mCurrentLocationOverlay.updatePosition(currentPosition);

		if (!hasUpdatedPosition) {
			mMapView.getController().animateTo(currentPosition);
			hasUpdatedPosition = true;
		}

		mMapView.invalidate();
	}

	private void setViewItemsVisibility(int visibility, boolean isNew) {
		final Button saveButton = (Button) findViewById(R.id.saveBtn);
		final Button deleteButton = (Button) findViewById(R.id.deleteBtn);
		;
		final Button testProviderButton = (Button) findViewById(R.id.testProviderBtn);
		;
		final EditText pONText = (EditText) findViewById(R.id.NotificationText);

		saveButton.setVisibility(visibility);
		testProviderButton.setVisibility(visibility);
		pONText.setVisibility(visibility);
		deleteButton.setVisibility(visibility);
		if (visibility == View.VISIBLE && isNew) {
			deleteButton.setVisibility(View.INVISIBLE);
		}
	}

	private void showNewPON() {
		isEditing = true;
		isNewPON = true;
		setViewItemsVisibility(View.VISIBLE, true);
		mEditOverlay = new EditPONOverlay(TobsnMapActivity.this.getResources()
				.getDrawable(R.drawable.arrow), this,
				mListener.getCurrentLocation());

		if (!mMapView.getOverlays().contains(mEditOverlay)) {
			mMapView.getOverlays().add(mEditOverlay);
		}

		mMapView.invalidate();
	}

	public void showPONPopup(long id) {
		isEditing = true;
		isNewPON = false;
		mCurrentID = id;
		mMapView.removeView(mPopup);

		Cursor c;
		mDBAdapter.open();
		c = mDBAdapter.fetchPON(id);

		GeoPoint p = new GeoPoint(c.getInt(DBOpenHelper.LATITUDE_INT),
				c.getInt(DBOpenHelper.LONGITUDE_INT));

		Button popupBtn = (Button) mPopup.findViewById(R.id.popupBtn);
		popupBtn.setText(c.getString(DBOpenHelper.TEXT_INT));
		popupBtn.setOnClickListener(mPopupClickListener);

		MapView.LayoutParams mapParams = new MapView.LayoutParams(
				ViewGroup.LayoutParams.WRAP_CONTENT,
				ViewGroup.LayoutParams.WRAP_CONTENT, p, 0, -25,
				MapView.LayoutParams.BOTTOM_CENTER);
		mMapView.addView(mPopup, mapParams);

		c.close();
		mDBAdapter.close();
		mMapView.invalidate();
	}

	private OnClickListener mSaveListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			// store data in db
			GeoPoint point = mEditOverlay.getPoint();
			String text = mPONText.getText().toString();
			int latitude = point.getLatitudeE6();
			int longitude = point.getLongitudeE6();
			mDBAdapter.open();
			if (isNewPON) {
				long id = mDBAdapter.createPON(text, latitude, longitude);

				Intent intent = new Intent(PROX_ALERT_INTENT);
				intent.putExtra(EXTRA_NOTIFICATION_ID, id);
				PendingIntent proximityIntent = PendingIntent.getBroadcast(
						getApplicationContext(), (int) id, intent, 0);

				mLocManager.addProximityAlert(latitude, longitude,
						POINT_RADIUS, PROX_ALERT_EXPIRATION, proximityIntent);
				Log.d("ProximityAlert", "latitude: " + latitude
						+ " longitude: " + longitude);

				GeoPoint p = mListener.getCurrentLocation();
				int lat = p.getLatitudeE6();
				int lng = p.getLongitudeE6();

				float results[] = new float[1];
				Location.distanceBetween(latitude, longitude, lat, lng, results);
				Log.d("Distance between", String.valueOf(results[0]));

			} else {
				mDBAdapter.updatePON(mCurrentID, text, latitude, longitude);
			}
			mDBAdapter.close();
			// update overlay
			mExistingNotifications.updateOverlay();
			// remove input overlay
			mMapView.getOverlays().remove(mEditOverlay);
			mPONText.setText(null);
			setViewItemsVisibility(View.INVISIBLE, false);

			mMapView.invalidate();

			isEditing = false;
		}
	};

	private OnClickListener mDeleteListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			mDBAdapter.open();
			mDBAdapter.deletePON(mCurrentID);

			Intent intent = new Intent(PROX_ALERT_INTENT);
			intent.putExtra(EXTRA_NOTIFICATION_ID, mCurrentID);
			PendingIntent proximityIntent = PendingIntent.getBroadcast(
					TobsnMapActivity.this, (int) mCurrentID, intent, 0);
			mLocManager.removeProximityAlert(proximityIntent);
			mDBAdapter.close();
			// update overlay
			mExistingNotifications.updateOverlay();
			// remove input overlay
			mMapView.getOverlays().remove(mEditOverlay);
			mPONText.setText(null);
			setViewItemsVisibility(View.INVISIBLE, false);

			mMapView.invalidate();

			isEditing = false;
		}
	};

	private OnClickListener mPopupClickListener = new OnClickListener() {

		@Override
		public void onClick(View v) {

			mMapView.removeView(mPopup);
			Cursor c;
			mDBAdapter.open();
			c = mDBAdapter.fetchPON(mCurrentID);
			mPONText.setText(c.getString(DBOpenHelper.TEXT_INT));

			GeoPoint p = new GeoPoint(c.getInt(DBOpenHelper.LATITUDE_INT),
					c.getInt(DBOpenHelper.LONGITUDE_INT));
			mEditOverlay = new EditPONOverlay(TobsnMapActivity.this
					.getResources().getDrawable(R.drawable.arrow),
					TobsnMapActivity.this, p);

			if (!mMapView.getOverlays().contains(mEditOverlay)) {
				mMapView.getOverlays().add(mEditOverlay);
			}
			c.close();
			mDBAdapter.close();
			setViewItemsVisibility(View.VISIBLE, false);

		}
	};

	private OnClickListener mTestProviderListener = new OnClickListener() {

		@Override
		public void onClick(View v) {

			Intent notificationIntent = new Intent(TobsnMapActivity.this,
					NotificationService.class);
			notificationIntent.putExtra("barTitle", "dingsda");
			notificationIntent.putExtra("contentTitle", "dungsda");
			String text = "hoppla";
			notificationIntent.putExtra("contentText", text);
			TobsnMapActivity.this.startService(notificationIntent);
		}
	};

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {

		if (resultCode != RESULT_CANCELED) {
			// When the user has chosen a notification from the list
			if (requestCode == NotificationListActivity.CHOOSE_NOTIFICATION) {
				Log.i("BLABLABLA", String.valueOf(resultCode));
				long id = data.getLongExtra(EXTRA_NOTIFICATION_ID, 0);

				Cursor c;
				mDBAdapter.open();
				c = mDBAdapter.fetchPON(id);
				GeoPoint p = new GeoPoint(c.getInt(DBOpenHelper.LATITUDE_INT),
						c.getInt(DBOpenHelper.LONGITUDE_INT));
				mMapView.getController().animateTo(p);
				c.close();
				mDBAdapter.close();
			}

			mExistingNotifications.updateOverlay();
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	@Override
	public void onBackPressed() {
		if (isEditing) {
			mMapView.removeView(mPopup);
			setViewItemsVisibility(View.INVISIBLE, false);

			mMapView.getOverlays().remove(mEditOverlay);
			isEditing = false;
		} else {
			super.onBackPressed();
		}
	}

	/**
	 * !!!!!!!!!!!!!!!!!!!! MENU !!!!!!!!!!!!!!!!!!!!!!!!!!
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.mapmenu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {
		case R.id.toggle_satellite:
			toggleSatellite();
			return true;

		case R.id.addNotification:
			showNewPON();
			return true;

		case R.id.showNotificationList:
			showNotificationList();
			return true;

		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void showNotificationList() {
		Intent intent = new Intent();
		intent.setClassName("tobsn.locationcalendar",
				"tobsn.locationcalendar.NotificationListActivity");
		startActivityForResult(intent,
				NotificationListActivity.CHOOSE_NOTIFICATION);
	}

	/**
	 * Toggles Satellite mode on the map. Initial is no satellite i guess.
	 */
	private void toggleSatellite() {
		if (isSatelite) {
			mMapView.setSatellite(false);
			isSatelite = false;
		} else {
			mMapView.setSatellite(true);
			isSatelite = true;
		}
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog;
		switch (id) {
		case 1:
			dialog = new Dialog(this);
			dialog.setContentView(R.layout.dialog);
			String text = mExistingNotifications.getSelectedItemText();

			dialog.setTitle("Notification");
			TextView textView = (TextView) dialog.findViewById(R.id.dialogText);
			textView.setText(text);
			break;
		default:
			dialog = null;
		}
		return dialog;
	}

	@Override
	protected void onResume() {
		super.onResume();
		mLocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0,
				0, mListener);
		mLocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
				mListener);
	}

	@Override
	protected void onPause() {
		super.onPause();
		mLocManager.removeUpdates(mListener);
	}
}
